#ifndef LINEARSYSTEM_INC
#define LINEARSYSTEM_INC

#include <cmath>
#include <omp.h>

#include "Matrix.h"
#include "Manager.h"

/*
 * =====================================================================================
 *        Class:  LinearSystem
 *  Description:  Classe que representa um sistema linear
 * =====================================================================================
 */
class LinearSystem
{

public:

    /*-----------------------------------------------------------------------------
     *  Contrói um sistema linear vazio
     *-----------------------------------------------------------------------------*/
    LinearSystem();

    /*-----------------------------------------------------------------------------
     *  Destrói o sistema linear
     *-----------------------------------------------------------------------------*/
    virtual ~LinearSystem();

    /*-----------------------------------------------------------------------------
     *  Resolve o sistema linear pelo método iterativo de Jacobi
     *-----------------------------------------------------------------------------*/
    void solve();

    /*-----------------------------------------------------------------------------
     *  Resolve o sistema linear pelo método iterativo de Jacobi de forma paralela
     *-----------------------------------------------------------------------------*/
    void parallelSolve();

    /*-----------------------------------------------------------------------------
     *  Verifica por convergência paralelamente pelo nó mestre
     *-----------------------------------------------------------------------------*/
    void parallelCheck();

    /*-----------------------------------------------------------------------------
     *  Verifica se o método de Jacobi já convergiu
     *-----------------------------------------------------------------------------*/
    bool hasConverged();

    /*-----------------------------------------------------------------------------
     *  Testa a linha desejada
     *-----------------------------------------------------------------------------*/
    double calcRow();

    /*-----------------------------------------------------------------------------
     *  Envia sinal de parada (convergência) do algoritmo
     *-----------------------------------------------------------------------------*/
    void sendStopSignal(char *stop, uint to);

	/*-----------------------------------------------------------------------------
	 *  Recebe sinal de parada (convergência) do algoritmo
	 *-----------------------------------------------------------------------------*/
    void recvStopSignal(char *stop, uint from);

    /*-----------------------------------------------------------------------------
     *  Adiciona os valores do sistema a partir de um stream de entrada
     *-----------------------------------------------------------------------------*/
    friend istream& operator >>(istream& is, LinearSystem& ls);

    /*-----------------------------------------------------------------------------
     *  Imprime os valores em um stream de saída
     *-----------------------------------------------------------------------------*/
    friend ostream& operator <<(ostream& os, LinearSystem& ls);

    /*-----------------------------------------------------------------------------
     *  Retorna a solução
     *-----------------------------------------------------------------------------*/
    mdoublePtr solution() { return x0; }

    /*-----------------------------------------------------------------------------
     *  Retorna ordem da matriz
     *-----------------------------------------------------------------------------*/
    uint getOrder() { return order; }

private:

    /*-----------------------------------------------------------------------------
     *  Ordem da matriz
     *-----------------------------------------------------------------------------*/
    uint order;

    /*-----------------------------------------------------------------------------
     *  Linha de teste
     *-----------------------------------------------------------------------------*/
    uint testRow;

    /*-----------------------------------------------------------------------------
     *  Erro máximo permitido
     *-----------------------------------------------------------------------------*/
    double error;

    /*-----------------------------------------------------------------------------
     *  Número máximo de iterações
     *-----------------------------------------------------------------------------*/
    ulong maxIt;

    /*-----------------------------------------------------------------------------
     *  Número de iterações feitas pelo método de Jacobi
     *-----------------------------------------------------------------------------*/
    ulong iterations;

    /*-----------------------------------------------------------------------------
     *  Matriz dos coeficientes
     *-----------------------------------------------------------------------------*/
    mdoublePtr A;

    /*-----------------------------------------------------------------------------
     *  Matriz dos termos independentes
     *-----------------------------------------------------------------------------*/
    mdoublePtr b;

    /*-----------------------------------------------------------------------------
     *  Matriz das variáveis
     *-----------------------------------------------------------------------------*/
    mdoublePtr x0;

    /*-----------------------------------------------------------------------------
     *  Matriz das variáveis
     *-----------------------------------------------------------------------------*/
    mdoublePtr x1;

};

#endif
